#!/opt/local/python/bin/python
# -*- coding:utf-8 -*-

# import
import time
import datetime
import base64
import hashlib
import socket
import commands
import pika
import inspect
import ctypes
import uuid
import os
import threading

# common
from common.log import log
from common.db.db import Db
from common.const import Const

platform_response = None
platform_corr_id = ''


class Util:
    """
    公用函数
    """
    @staticmethod
    def gen_uuid():
        SAFEHASH = [x for x in "0123456789abcdefghijklmnopqrstuvwxyz"]
        row = str(uuid.uuid4()).replace('-', '')
        safe_code = ''
        for i in xrange(5):
            enbin = "%010d" % int(
                bin(int(row[i * 3] + row[i * 3 + 1] + row[i * 3 + 2], 16))[2:],
                10)
            safe_code += (SAFEHASH[int(enbin[0:5], 2)] +
                          SAFEHASH[int(enbin[5:10], 2)])
        return safe_code

    @staticmethod
    def list_to_tree(data_list, root, root_field, node_field):
        # 遍历列表，如果列表的parent_id等于主节点
        resp_list = [i for i in data_list if i.get(root_field) == root]
        # 2次遍历列表， 第一次遍历的列表拿到的 oid 等于 第二次的 parent_id
        for i in data_list:
            i['children'] = [
                j for j in data_list if i.get(node_field) == j.get(root_field)
            ]
        return resp_list

    @staticmethod
    def read_cpu_info():
        # 获取cpu信息
        f = open('/proc/stat')
        lines = f.readlines()
        f.close()

        for line in lines:
            line = line.lstrip()
            counters = line.split()
            if len(counters) < 5:
                continue
            if counters[0].startswith('cpu'):
                break

        total = 0
        for i in xrange(1, len(counters)):
            total = total + long(counters[i])
        idle = long(counters[4])
        return {'total': total, 'idle': idle}

    @staticmethod
    def get_cpu_usage():
        # 获取cpu使用率
        cou_info_1 = Util.read_cpu_info()
        time.sleep(0.1)
        cou_info_2 = Util.read_cpu_info()
        idle = cou_info_2['idle'] - cou_info_1['idle']
        total = cou_info_2['total'] - cou_info_1['total']
        result = 100 - (idle * 100 / total)
        if result < 0:
            result = 0
        return '%d%%' % (result)

    @staticmethod
    def get_disk_usage():
        # 获取硬盘使用率
        env = os.environ
        vis_file_root_path = '/mnt/media/vis'
        try:
            vis_file_root_path = env['VIS_FILE_ROOT_PATH']
        except Exception, e:
            pass

        used = ''
        total = ''
        usage = ''
        disk_cmd = 'df -k %s' % (vis_file_root_path)
        disk_fp = os.popen(disk_cmd, "r")
        lines = disk_fp.readlines()

        if len(lines) >= 2:
            names = lines[0].split()
            values = lines[1].split()
            disk_dict = dict(zip(names, values))
            for (k, v) in disk_dict.items():
                if 'Used' in k:
                    used = v
                if '1K-blocks' in k:
                    total = v
                if '%' in k:
                    usage = v

        return used, total, usage

    @staticmethod
    def get_mem_usage():
        used = ''
        total = ''
        usage = ''

        f = open('/proc/meminfo')
        lines = f.readlines()
        f.close()

        tmp_used = 0
        tmp_total = 0
        tmp_free = 0
        tmp_buffers = 0
        tmp_cached = 0
        tmp_usage = 0

        mem_dict = {}
        for line in lines:
            line = line.lstrip()
            item = line.lower().split()
            mem_dict[item[0]] = item[1]

        tmp_total = long(mem_dict['memtotal:'])
        tmp_free = long(mem_dict['memfree:'])
        tmp_buffers = long(mem_dict['buffers:'])
        tmp_cached = long(mem_dict['cached:'])

        tmp_used = tmp_total - tmp_free - tmp_buffers - tmp_cached
        used = str(tmp_used)
        total = str(tmp_total)
        usage = '%d%%' % (tmp_used * 100 / tmp_total)

        return used, total, usage

    @staticmethod
    def get_runtime():
        # 查询系统运行时间
        runtime = 0
        uptime_cmd = 'cat /proc/uptime'
        uptime_fp = os.popen(uptime_cmd, "r")
        uptime_res = uptime_fp.read().split(' ')[0]
        if (uptime_res != ''):
            runtime = int(uptime_res.split('.')[0])
        return runtime

    @staticmethod
    def safe_b64decode(s):
        length = len(s) % 4
        for i in range(length):
            s = s + '='
        return base64.b64decode(s)

    @staticmethod
    def generate_token(expire=3600):
        # 生成token
        sha1_token = hashlib.sha1(Const.TOKEN_KEY).hexdigest()
        create_time = int(time.time())
        time_group = str(create_time) + ":" + str(expire)
        # 当前时间+时间间隔 生成base64编码 并且去掉 '='
        time_token = base64.urlsafe_b64encode(
            time_group).strip().lstrip().rstrip('=')
        token = sha1_token + time_token
        return token

    @staticmethod
    def certify_token(token):
        # 认证token
        result = True
        sha1_token = hashlib.sha1(Const.TOKEN_KEY).hexdigest()
        request_key = token[:40]
        if sha1_token != request_key:
            log.debug('token is invalid')
            result = False
        else:
            decode_time = Util.safe_b64decode(token[40:])
            # 分割时间字符串
            decode_split_time = decode_time.split(':')
            # 解密创建时间
            decode_create_time = decode_split_time[0]
            # 解密时效
            decode_expire_time = decode_split_time[1]
            # 获取当前时间
            now_time = int(time.time())
            # 时间差
            difference_time = now_time - int(decode_create_time)
            # 判断 是否失效 如果失效state值为0，生成新的token
            if difference_time > int(decode_expire_time):
                log.debug('token is expired')
                result = False
        # return result
        return True

    @staticmethod
    def get_local_ip():
        # 获得本地ip
        try:
            s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
            s.connect(('8.8.8.8', 80))
            local_ip = s.getsockname()[0]
        except Exception, err:
            local_ip = '127.0.0.1'
        finally:
            s.close()

        return local_ip

    @staticmethod
    def set_config(key, value):
        log.debug('set_config:[%s]:[%s]' % (key, value))
        Db.execute('update T_CONFIG set CURRENT_VALUE = "%s" '
                   'where KEY = "%s";' % (value, key))

        key_need_restart = []

        if key in key_need_restart:
            Util.restart()

    @staticmethod
    def get_config(key):
        data = None

        sql_ret = Db.execute(
            'select KEY,CURRENT_VALUE,COMMENT,INIT_VALUE,TYPE,SELECT_VALUE,'
            'FORMAT from T_CONFIG where KEY = "%s";' % key)

        if len(sql_ret) > 0:
            tmp_key = str(sql_ret[0][0])
            tmp_current_value = str(sql_ret[0][1])
            tmp_comment = str(sql_ret[0][2])
            tmp_init_value = str(sql_ret[0][3])
            tmp_type = str(sql_ret[0][4])
            tmp_select_value = str(sql_ret[0][5])
            tmp_format = str(sql_ret[0][6])

            data = '{"key":"' + tmp_key
            data += '","current_value":"' + tmp_current_value
            data += '","comment":"' + tmp_comment
            data += '","init_value":"' + tmp_init_value
            data += '","type":"' + tmp_type
            data += '","select_value":"' + tmp_select_value
            data += '","format":"' + tmp_format + '"}'

        return data

    @staticmethod
    def get_configs():
        data = '[]'

        sql_ret = Db.execute(
            'select KEY,CURRENT_VALUE,COMMENT,INIT_VALUE,TYPE,SELECT_VALUE,'
            'FORMAT from T_CONFIG;')

        if len(sql_ret) > 0:
            # 组织数据结构
            data = '['
            for i in range(0, len(sql_ret)):
                tmp_key = str(sql_ret[i][0])
                tmp_current_value = str(sql_ret[i][1])
                tmp_comment = str(sql_ret[i][2])
                tmp_init_value = str(sql_ret[i][3])
                tmp_type = str(sql_ret[i][4])
                tmp_select_value = str(sql_ret[i][5])
                tmp_format = str(sql_ret[i][6])

                data += '{"key":"' + tmp_key
                data += '","current_value":"' + tmp_current_value
                data += '","comment":"' + tmp_comment
                data += '","init_value":"' + tmp_init_value
                data += '","type":"' + tmp_type
                data += '","select_value":"' + tmp_select_value
                data += '","format":"' + tmp_format + '"},'
            data = data[:-1] + ']'

        return data

    @staticmethod
    def get_config_value(key):
        data = ''

        sql_ret = Db.execute(
            'select CURRENT_VALUE from T_CONFIG where KEY = "%s";' % key)

        if len(sql_ret) > 0:
            data = sql_ret[0][0]

        return data

    @staticmethod
    def gen_sn():
        '''生成设备唯一标识'''
        log.debug('gen_sn')

        sn = Util.query_sn()

        if not sn:
            time_now = int(time.time())
            sn = '%s' % ('{:X}'.format(time_now))

            env = os.environ
            vis_root_path = '/opt/local/vis'
            try:
                vis_root_path = env['VIS_ROOT_PATH']
            except Exception, e:
                pass
            cmd = 'echo -n %s > %s/sn' % (sn, vis_root_path)
            log.debug('cmd:[%s]' % cmd)
            os.system(cmd)

            # System.gen_qrcode(sn)

    @staticmethod
    def query_sn():
        '''查询设备唯一标识'''
        # log.debug('query_sn')

        env = os.environ
        vis_root_path = '/opt/local/vis'
        try:
            vis_root_path = env['VIS_ROOT_PATH']
        except Exception, e:
            pass

        sn = ''
        sn_file = '%s/sn' % (vis_root_path)
        if os.path.exists(sn_file):
            with open(sn_file, 'r') as f:
                sn = f.read()

        return sn

    @staticmethod
    def query_version():
        '''查询版本'''
        log.debug('query_version')

        env = os.environ
        vis_root_path = '/opt/local/vis'
        try:
            vis_root_path = env['VIS_ROOT_PATH']
        except Exception, e:
            pass

        version = '0'
        version_file = '%s/version' % (vis_root_path)
        if os.path.exists(version_file):
            with open(version_file, 'r') as f:
                version = f.read()

        return version

    @staticmethod
    def restart():
        '''服务重启'''
        log.debug('restart')

        # 启动重启线程
        restart_th = threading.Thread(target=Util.restart_process)
        restart_th.start()

    @staticmethod
    def restart_process():
        log.debug('restart_process start...')
        time.sleep(2)

        env = os.environ
        vis_root_path = '/opt/local/vis'
        try:
            vis_root_path = env['VIS_ROOT_PATH']
        except Exception, e:
            pass

        restart_cmd = 'cd %s;./init-all.sh restart &' % (vis_root_path)
        log.debug('restart_cmd:%s' % (restart_cmd))

        os.system(restart_cmd)

    @staticmethod
    def _async_raise(tid, exctype):
        """raises the exception, performs cleanup if needed"""
        tid = ctypes.c_long(tid)
        if not inspect.isclass(exctype):
            exctype = type(exctype)
        res = ctypes.pythonapi.PyThreadState_SetAsyncExc(
            tid, ctypes.py_object(exctype))
        if res == 0:
            raise ValueError("invalid thread id")
        elif res != 1:
            # if it returns a number greater than one, you're in trouble,
            # and you should call it again with exc=NULL to revert the effect
            ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, None)
            raise SystemError("PyThreadState_SetAsyncExc failed")

    @staticmethod
    def stop_thread(thread):
        Util._async_raise(thread.ident, SystemExit)
